home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
EnigmA Amiga Run 1995 October
/
EnigmA AMIGA RUN 01 (1995)(G.R. Edizioni)(IT)[!][issue 1995-10][Aminet 7].iso
/
Aminet
/
misc
/
emu
/
prlink_amiga.lha
/
prlink-0.8.0a
/
src
/
prserver.asm
< prev
next >
Wrap
Assembly Source File
|
1995-05-12
|
21KB
|
1,177 lines
.processor 6502
.include "options.inc"
#if target & c128
host = 128
#endif
#if target & c64
host = 64
#endif
#if target & vic20
host = 20
#endif
#if target & (pet3001 | pet4001)
host = 201 ; want 2001 but it must fit in a byte
#endif
#if target & (c128 | c64)
#if ramexp & piaexp
pia = $d7f0 ; the PIA base address. See also the definition "bank".
#endif
#if ramexp & reuexp
reu = $df00 ; the REU base address. See also the definition "bank".
reubmin = $10 ; smallest bank number that refers to the REU banks
#endif
#endif
; The machines with a VIA that use a VIA control line for handshaking
; must reset the interrupt flag before it can be used again.
clearviaifr = target & (vic20 | pet3001 | pet4001)
; The following constant tells if the cable uses the PA2 handshaking line
pa2_used = cable & (pc64 | prlink | prlink88)
seg MAIN
.org prsrv
#if target & (vic20 | c64 | c128)
strval = $10 ; strobe bit value on the Vic-20/C64/C128
start = $ac ; some memory locations
end = $ae
cinv = $314
#endif
#if cable & (pc64 | c64net | transnib)
#if target & (pet3001 | pet4001)
stemp = $bd ; memory place that holds the byte that will be received
#else
stemp = $a7 ; memory place that holds the byte that will be received
#endif
#endif
#if target & c128
bstart = $2d ; start of basic program text
bend = $1210 ; end of basic program text
bank = $a9 ; temporary variable that holds the memory bank
stack = $105 ; offset to the stack while in interrupt
peek = $2a2
peekptr = $2aa
poke = $2af
pokeptr = $2b9
linkprg = $4f4f
basrun = $5aa6
ackval = 4
ack = $dd00
data = $dd01
ddr = $dd03
strobe = $dd0d
#endif
#if target & c64
bstart = $2b ; start of basic program text
bend = $2d ; end of basic program text
#if ramexp
bank = $a9 ; temporary variable that holds the memory bank
#else
bank = none ; non-banked systems
#endif
blnsw = $cc
crsw = $d0
stack = $104 ; offset to the stack while in interrupt
clr = $a659
linkprg = $a533
stxpt = $a68e
newstt = $a7ae
ackval = 4
ack = $dd00
data = $dd01
ddr = $dd03
strobe = $dd0d
#endif
#if target & vic20
bstart = $2b ; start of basic program text
bend = $2d ; end of basic program text
bank = none
blnsw = $cc
crsw = $d0
stack = $104 ; offset to the stack while in interrupt
clr = $c659
linkprg = $c533
stxpt = $c68e
newstt = $c7ae
ackval = $20
ack = $911c
data = $9110
ddr = $9112
strobe = $911d
#endif
#if target & (pet3001 | pet4001)
start = $c7 ;; the PET series
end = $c9
cinv = $0090
bstart = $28 ; start of basic program text
bend = $2a ; end of basic program text
blnsw = $a7
crsw = $ac
#if ramexp & pet96
bank = $bf ; temporary variable that holds the memory bank
latch = $fff0 ; write-only register
#else
bank = none ; non-banked systems
#endif
stack = $104 ; offset to the stack while in interrupt
ackval = $20 ; CB2 value bit when set to manual control
ack = $e84c ; VIA CRB
data = $e84f ; VIA PA without handshake
ddr = $e843 ; VIA DDRA
strval = $02 ; VIA CA1 bit in IFR
strobe = $e84d ; VIA IFR
#endif
#if target & pet4001 ; for BASIC 4.0
clr = $b5e9
linkprg = $b4b6
stxpt = $b622
newstt = $b74a
#endif
#if target & pet3001 ; for BASIC 2.0
clr = $c572
linkprg = $c442
stxpt = $c5a7
newstt = $c6c4
#endif
cmdinfo = 0 ; code for requesting machine type info
cmdload = 1 ; code for loading
cmdsave = 2 ; code for saving
cmdjump = 3 ; code for jumping to an address
cmdrun = 4 ; code for running a BASIC program
mystart: ; A jump table for external programs
jmp install ; Installs the prserver wedge.
jmp deinstall ; Removes the prserver wedge.
jmp send_switch ; Switches to send configuration, and sends a byte.
jmp send ; Sends a byte assuming send configuration.
jmp receive_switch ; Switches to receive configuration, and receives a byte.
jmp receive ; Receives a byte assuming receive configuration.
jsr install ; Reinstalls the prserver wedge and
#if target & c128 ; continues with the previous program.
jmp $ff33
#else
pla
tay
pla
tax
pla
rti
#endif
install:
sei
lda cinv ; check the original IRQ vector
ldx cinv+1
cmp #<irq
bne irqinit
cpx #>irq
beq skipirq
irqinit: ; if it was different from our irq wedge, install the wedge
sta oldirq ; first save the old IRQ vector
stx oldirq+1
lda #<irq ; and then install ours
sta cinv
lda #>irq
sta cinv+1
skipirq:
#if ramexp & piaexp
#if target & c128
lda #$3e
sta $ff00
#endif
ldx #11 ; initialize the PIA
0$:
lda piatable-1,x
sta pia,x
dex
bne 0$
#endif
#if cable & (prlink | prlink88 | pc64)
#if target & vic20
lda #$ef
and ack
sta ack ; set CB1 to trigger on falling edge
#endif
#if target & (pet3001 | pet4001)
lda ack
and #%11111110; set CA1 to trigger on falling edge
ora #%11100000; set CB2 to output with manual control
sta ack
#endif
#endif
#if cable & transnib
lda #$40 ; prepare for input: only DRCV is output
sta data ; idle state of lines is high
sta ddr
#endif
cli
rts
#if ramexp & piaexp
piatable:
.byte $34,$fe,4,$ff,0,$ff,0,$dc,4,$fe,4
#endif
irq:
#if (target & c64) * pa2_used
lda #ackval ; this is needed for Action Replay, whose fastload command
ora ack ; resets the PA2 line
sta ack
#endif
#if cable & (prlink | prlink88)
lda #strval
bit strobe ; check the -FLAG signal
beq return ; jump if the client didn't want to send anything
ldx #0
stx ddr ; restore the data lines to inputs
#endif
#if cable & pc64
lda #strval
bit strobe ; check the -FLAG signal
beq return ; jump if the client didn't want to send anything
ldx #$f
stx ddr ; restore the data lines to inputs/outputs
#endif
#if cable & c64net
lda data
and #$F8 ; check if the remote host wants to send a byte
eor #8
bne return ; jump if not
lda #$7
sta data
sta ddr
#endif
#if cable & transnib
bit data ; test if DRDY is low.
bmi return
lda #$40 ; prepare for input: only DRCV is output
sta data ; idle state of lines is high
sta ddr
#endif
jsr rereceive ; receive byte without requiring handshaking
cmp #cmdinfo
bne load ; branch if the client did not request for host info
lda #host ; return the host info byte
jsr send_switch
lda #<mystart ; tell the driver start address
jsr send
lda #>mystart
jsr send
lda bstart ; and the BASIC start address
jsr send
lda bstart+1
jsr send
return:
oldirq = * + 1
jmp * ; continue the normal irq (selfmodifying code)
load:
cmp #cmdload ; was it the command for loading?
beq 0$
jmp jump ; no, skip
0$:
jsr gethdr ; get the addresses
#if bank
lda bank ; other bank than the default specified => can't be basic
bne 1$
#endif
lda start ; check if it is a basic program
eor bstart
bne 1$
lda start+1
eor bstart+1
1$:
pha ; accu is 0 if it is a basic program
#if target & (c64 | c128)
lda $d011
pha
lda $d030
pha
lda #$1
sta $d011 ; blank the screen
sta $d030 ; switch to 2 MHz mode
#endif
#if ramexp & reuexp
lda bank
cmp #reubmin ; is it a REU bank?
bcc 14$ ; no, do not save REC registers on stack
#if actionreuplay
lda #$2a
sta $de00 ; enable Action Replay RAM at $df00 (disable the ROM)
; Action Replay has one write-only I/O register at $de00-$deff.
; Its bits are as follows:
; 7 - not used
; 6 - probably resets the IRQ/NMI flipflop in the freezer mode
; 5 - enables RAM at I/O2
; 4 - bank selector
; 3 - bank selector
; 2 - 1=cartridge off
; 1 - 1=-EXROM high
; 0 - 1=-GAME low
#else
ldx #10
11$:
lda reu,x
pha
dex
bne 11$
#endif
lda end+1 ; store the end of file pointer high byte
pha
jsr reuinit ; initialize the REU registers. C flag is set at this stage.
12$:
jsr receive
sta (start),y
jsr incmptreu
bne 12$
dec $d030 ; switch to 1 MHz mode
lda #$f2
sta reu+1 ; swap the REU memory back
pla
sta start+1 ; adjust the end address pointers
sta end+1
#if actionreuplay
lda #$0a
sta $de00 ; restore normal Action Replay configuration
#else
ldx #0
13$:
inx
pla
sta reu,x
cpx #10
bne 13$
#endif
jmp endload
14$:
#endif
#if ramexp & piaexp
lda end+1 ; store the end of file pointer high byte
pha
lda pia ; store the PIA memory configuration
pha
#if target & c128
lda $d506 ; store the common memory configuration
pha
#endif
jsr piainit ; initialize the PIA expansion (with $d506 value in A)
2$:
jsr receive
sta (start),y
jsr incmptr
bne 2$
#if target & c128
pla ; restore the original MMU banking
ldx #0 ; enable all ROMs, select RAM bank 0
stx $d500
sta $d506 ; restore the common memory configuration
#endif
pla
sta pia
pla
sta start+1 ; adjust the end address pointers
sta end+1
#else
#if target & c128
lda pokeptr
pha
lda #start
sta pokeptr
2$:
jsr receive ; get the bytes
ldx bank
jsr poke
jsr incmptr ; update the pointer
bne 2$
sty bank
pla
sta pokeptr
#else
2$:
jsr receive ; get the bytes
sta (start),y
jsr incmptr ; update the pointer
bne 2$
#endif
#endif
endload:
#if target & (c64 | c128)
pla
sta $d030 ; restore original speed
pla
sta $d011 ; and screen mode
#endif
pla
bne 0$ ; it was not a basic program
lda end ; set the basic end address
sta bend
lda end+1
sta bend+1
jsr linkprg ; relink the program
#if target & c128
lda #0
sta $ff00 ; restore the MMU configuration (linkprg changes it)
#endif
0$:
jmp (oldirq)
jump:
cmp #cmdjump ; was it the command for jumping?
bne save ; no, skip
jsr receive ; get the memory configuration (for the c128)
#if target & c128
sta bank ; and temporarily store it
#endif
jsr receive ; get the jump address low
tax
jsr receive ; get the jump address high
pha ; and store it
txa
pha ; store the jump address low
lda #0
pha ; clear the flags
pha ; and the registers
pha
pha
#if target & c128
lda bank
pha ; store the MMU configuration
#endif
jsr deinstall ; deinstall the IRQ routine
#if target & c128
#else
sta crsw ; turn the cursor off
sta blnsw
#endif
jmp (oldirq)
save:
cmp #cmdsave
bne run
#if target & (c64 | c128)
lda $d011
pha
lda $d030
pha
lda #$1
sta $d011 ; blank the screen
sta $d030 ; switch to 2 MHz mode
#endif
jsr gethdr ; get the pointers
#if ramexp & reuexp
lda bank
cmp #reubmin ; is it a REU bank?
bcc 14$ ; no, jump to normal save
#if actionreuplay
lda #$2a
sta $de00 ; disable Action ROM at $df00
#else
ldx #10
11$:
lda reu,x ; store the REU registers
pha
dex
bne 11$
#endif
lda end+1 ; store the end of file pointer high byte
pha
jsr reuinit ; initialize the REU registers. C flag is set at this stage.
12$:
lda (start),y
jsr send
jsr incmptreu
bne 12$
dec $d030 ; switch to 1 MHz mode
lda #$f2
sta reu+1 ; swap the REU memory back
pla
sta start+1
sta end+1
#if actionreuplay
lda #$0a
sta $de00 ; restore normal Action Replay configuration
#else
ldx #0
13$:
inx
pla
sta reu,x
cpx #10
bne 13$
#endif
jmp endsave
14$:
#endif
#if ramexp & piaexp
lda pia ; store the PIA memory configuration
pha
#if target & c128
lda $d506 ; store the common memory configuration
pha
#endif
jsr piainit ; initialize the PIA expansion (with $d506 value in A)
0$:
lda (start),y
jsr send
jsr incmptr
bne 0$
#if target & c128
pla
ldx #0
stx $d500
sta $d506
#endif
pla
sta pia
#else
#if target & c128
lda peekptr
pha
lda #start
sta peekptr
0$:
ldx bank
jsr peek
jsr send
jsr incmptr
bne 0$
sty bank
pla
sta peekptr
#else
#if target & c64
ldx 1
0$:
lda #$34
sta 1 ; switch to 64 kB RAM config
lda (start),y
stx 1 ; restore the normal config
#else
0$:
lda (start),y
#endif
jsr send
jsr incmptr
bne 0$
#endif
#endif
endsave:
#if target & (c64 | c128)
pla
sta $d030 ; restore original speed
pla
sta $d011 ; and screen mode
#endif
return2:
jmp (oldirq) ; return from interrupt
run:
cmp #cmdrun
bne return2
jsr deinstall ; Install the original interrupt routine
#if target & c128
cli ; process the pending interrupt in a very kludgeous manner.
jmp basrun
#else
sta crsw ; turn the cursor off
sta blnsw
cli ; process the pending interrupt in a very kludgeous manner.
jsr clr ; The stack won't run out, since the BASIC clr call
; initializes the stack pointer.
jsr stxpt ; Set the BASIC text pointer (to the beginning of the prg)
jmp newstt ; BASIC warm start
#endif
deinstall: ; restore the original interrupt routine
lda oldirq
sta cinv
lda oldirq+1
sta cinv+1
rts
gethdr:
jsr receive ; get the memory bank byte
#if ramexp
sta bank
#else
#if target & c128
lsr
ror
ror
ora #$3f
sta bank
#endif
#endif
lda #0 ; send the acknowledgement code 0
jsr send_switch
jsr receive_switch ; get the file start and end vectors
sta start
jsr receive
sta start+1
jsr receive
sta end
jsr receive
sta end+1
rts
#if ramexp & piaexp
incmptr: ; increment and compare the current byte pointer
inc start ; and change the PIA bank if necessary.
bne 0$
inc start+1
bpl 0$
dex ; decrease the bank jump counter
lda #$40
sta start+1 ; restore the address
clc
lda #$10
adc pia
sta pia ; and adjust the PIA bank
0$:
txa ; is it the last bank?
bne 1$ ; no, return
lda start ; perform the comparison
cmp end
bne 1$
lda start+1
cmp end+1
1$:
rts
#else
incmptr: ; increment and compare the current byte pointer.
inc start ; increment.
bne 0$
inc start+1
0$:
lda start ; compare. if start == end, the zero flag will be set.
cmp end
bne 1$
lda start+1
cmp end+1
1$:
rts
#endif
#if ramexp & reuexp
incmptreu:
inc start ; increment and compare the current byte pointer
bne 0$ ; and transfer another REU block in if necessary.
inc start+1
bpl 0$
dex ; decrease the bank jump counter
dec $d030 ; slow down to 1 MHz
lda #$f2
sta reu+1 ; swap the buffers
lda #$40
sta start+1 ; restore the REU buffer address
clc
#if actionreuplay
adc bank
sta bank
#else
adc reu+5
#endif
sta reu+5 ; update the REU memory pointer
lda #$f2
sta reu+1 ; swap the buffers
inc $d030 ; switch back to 2 MHz mode
0$:
txa ; is it the last bank?
bne 1$ ; no, return
lda start ; perform the comparison
cmp end
bne 1$
lda start+1
cmp end+1
1$:
rts
#endif
#if cable & (prlink | prlink88)
; .A := data, .Y := 00, .X preserved
receive_switch:
;;; wait for first part of handshake
lda #strval
1$:
bit strobe ; wait for handshaking
beq 1$
#if clearviaifr
sta strobe
#endif ; clearviaifr
;;; and only then switch data direction.
lda #0 ; switch back to inputs
sta ddr
beq receive1 ; branch always
receive:
#if clearviaifr
rereceive: ; rereceive (without handshake) is only different for the CIA
#endif
lda #strval
0$:
bit strobe ; wait for handshaking
beq 0$
#if clearviaifr
sta strobe
#else
rereceive: ; rereceive (receive without handshaking) for the CIA
#endif ; clearviaifr
receive1:
lda #ackval
eor ack
ldy data ; read the byte
sta ack ; acknowledge
tya
ldy #0
rts
; .A trashed, .Y := 00, .X preserved
send_switch:
;;; wait for first part of handshake
tay
lda #strval
1$:
bit strobe ; wait for handshaking
beq 1$
#if clearviaifr
sta strobe
#endif
;;; and only then switch data direction.
#if cable & prlink88
lda #$ff
#else
lda #$0f
#endif
sta ddr ; set the data lines to output
bne send1 ; branch always
send:
tay
lda #strval
0$:
bit strobe ; wait for handshaking
beq 0$
#if clearviaifr
sta strobe
#endif
send1:
#if cable & prlink88
#else
tya
sta data ; send the low nybble
lsr
lsr
lsr
lsr
tay ; move the high nybble to y
lda #ackval
eor ack
sta ack ; ack: the low nybble is on the bus
lda #strval
1$:
bit strobe ; handshake
beq 1$
#if clearviaifr
sta strobe
#endif ; via
#endif ; prlink88
sty data ; send the high nybble (or the whole byte, for prlink88)
ldy #0
lda ack
eor #ackval
sta ack ; ack: the high nybble is on the bus
rts
#endif ; prlink | prlink88
#if cable & pc64
; .A := data, .Y := 00, .X preserved
receive_switch:
receive:
#if clearviaifr
rereceive:
#endif
lda #strval
0$:
bit strobe ; wait for handshaking
beq 0$
#if clearviaifr
sta strobe
#else
rereceive:
#endif
lda ack
and #255 - ackval
ldy data
sta ack
tya
lsr
lsr
lsr
lsr
sta stemp
lda #strval
1$:
bit strobe
beq 1$
#if clearviaifr
sta strobe
#endif
lda ack
ora #ackval
tay
lda data
sty ack
and #$F0
ora stemp
ldy #0
rts
; .A trashed, .Y := 00, .X preserved
send_switch:
send:
tay
lda #strval
0$:
bit strobe ; wait for handshaking
beq 0$
#if clearviaifr
sta strobe
#endif
sty data
lda ack
and #255 - ackval
sta ack
tya
lsr
lsr
lsr
lsr
tay
lda #strval
1$:
bit strobe ; wait for handshaking
beq 1$
#if clearviaifr
sta strobe
#endif
sty data
lda ack
ora #ackval
sta ack
ldy #0
rts
#endif ; pc64
#if cable & c64net
; .A := data, .Y := 00, .X preserved
receive_switch:
receive:
rereceive:
lda #8
0$:
bit data ; initial handshaking
beq 0$
lda data ; get the high nybble
and #$f0
sta stemp
lda #8
sta data ; acknowledge (place 0 on PB2)
1$:
bit data ; wait for acknowledgement
bne 1$
ldy #4
lda data ; get the low nybble
sty data ; acknowledge
ldy #0
lsr
lsr
lsr
lsr
ora stemp
rts
; .A trashed, .Y := 00, .X preserved
send_switch: ; switch to sending and send
send:
tay
0$:
lda data ; initial handshaking
and #$f8
eor #$f0
bne 0$
lda #0
sta data
1$:
lda data
bne 1$
tya
ora #4
sta data ; send the lowest bit pair
lda #8
2$:
bit data ; wait for acknowledgement
beq 2$
tya
lsr
lsr
tay
and #3
sta data ; send the lowest bit pair but one
lda #8
3$:
bit data ; wait for acknowledgement
bne 3$
tya
lsr
lsr
tay
ora #4
sta data ; send the highest bit pair but one
lda #8
4$:
bit data ; wait for acknowledgement
beq 4$
tya
lsr
lsr
sta data ; send the highest bit pair
lda #8
5$:
bit data ; wait for acknowledgement
bne 5$
lda #4
sta data
ldy #0
rts
#endif ; pc64
#if cable & transnib
; .A := data, .Y := 00, .X preserved
receive_switch:
lda #$40 ; $40 is DRCV (output), $80 is DRDY (input)
sta ddr
receive:
rereceive:
jsr recvnyb ; high nybble first
asl
asl
asl
asl
sta stemp
jsr recvnyb
ldy #0 ; (y is preserved in this function)
ora stemp
rts
recvnyb:
rdrdyhi:
bit data ; - Receiver starts waiting for DRDY to go low.
bmi rdrdyhi
; - Sender puts nybble on data lines, pulls DRDY low and waits
; for DRCV to go low.
lda data ; - Receiver gets nybble,
and #$ff-$40 ; pulls DRCV low
sta data
rdrdylo:
bit data ; and waits for DRDY to go high.
bpl rdrdylo
; - Sender pulls DRDY high and waits for DRCV to go high.
ora #$40
sta data ; - Receiver pulls DRCV high
and #$0f
rts
; .A trashed, .Y := 00, .X preserved
send_switch:
ldy #$4f ; $80 is DRCV (input), $40 is DRDY (output)
sty ddr ; note that the names are swapped from receiving but the
; data direction isn't!
send:
tay ; high nybble first
lsr
lsr
lsr
lsr
jsr sendnyb
tya
and #$0f ; fall through to send low nybble
ldy #0 ; clear y
sendnyb: ; - Receiver starts waiting for DRDY to go low.
sta data ; - Sender puts nybble on data lines, pulls DRDY low and
rdrcvhi:
bit data ; waits or DRCV to go low.
bmi rdrcvhi
; - Receiver gets nybble, pulls DRCV low
; and waits for DRDY to go high.
ora #$40 ; - Sender pulls DRDY high and
sta data
rdrcvlo:
bit data ; waits for DRCV to go high.
bpl rdrcvlo
rts
#endif
#if ramexp & piaexp
piainit:
#if target & c128
ora #$3f ; the accu must be loaded with $d506 when calling this routine
sta $d506 ; set the MMU configuration to 32kB common memory (top and low)
lda bank
and #$f
lsr
ror
ror
tax
and #$c0
ora #2
sta $d500 ; set the MMU banking (disabling the BASIC ROM)
txa
ror
ror
#else
lda bank
asl
asl
asl
asl
#endif
eor #$c0
and #$c0
ora #$c
sta pia ; store the PIA banking configuration
lda start+1
lsr
lsr
and #$30
ora pia
sta pia ; set the initial PIA configuration
#endif
#if ramexp
rptrinit:
sec
lda end+1
ora #$3f
sbc start+1 ; get the amount of bank crossings
asl
rol
rol
and #3
tax ; and store it to x
bne 0$ ; check for address wraparound
lda start
cmp end ; if start >= end, the amount of bank crossings will be 4.
lda start+1
sbc end+1
bcc 0$
ldx #4
0$:
lda start+1
and #$3f
ora #$40
sta start+1
lda end+1
and #$3f
ora #$40
sta end+1
rts
#endif
#if ramexp & reuexp
reuinit:
lda #0
ldx #$40
sta reu+2 ; set the buffer address for the C64/C128
stx reu+3
sta reu+7 ; set the buffer length
stx reu+8
sta reu+9 ; reset some other registers
sta reu+10
lda bank
sbc #reubmin ; set the memory bank (C flag initially set)
sta reu+6
lda start ; set the start address in the REU
sta reu+4
lda start+1
sta reu+5
#if actionreuplay
sta bank
#endif
#if target & c128
lda #2
sta $ff00 ; switch to RAM bank 0 and disable the BASIC ROM
#endif
dec $d030 ; slow down to 1 MHz
lda #$f2
sta reu+1 ; swap the buffers
inc $d030 ; speed up again
jmp rptrinit
#endif